function VNode(tag,data,children,text){
  return {
    tag:tag,
    data:data,
    children:children,
    text:text
  }
}
class Dep {
  constructor() {
    this.subs = []
  }
  add(cb) {
    this.subs.push(cb)
  }
  notify() {
    this.subs.forEach((cb) => cb())
  }
}
Dep.target = null;
function watch(vm, exp, cb){
  Dep.target = cb
  return exp()
}
  class Vue {
      constructor(options) {
        //this.__props__={};
        this.$options = options;
        this._data = options.data;
        this._el=document.querySelector(options.el);
        this._methods=options.methods;
        observer(options.data);
        Object.keys(options.data).forEach(key => this._proxy(key));
        parseMethod.bind(this);
        parseMethod(options.methods);
        var vodm= watch(this,this._render.bind(this),this._update.bind(this));
        Dep.target=null;
        console.log(vodm)
        //this._update();
      }
     _update() {
        console.log("我需要更新");
        const vdom = this._render.call(this)
      }
      _render(){
        return this.$options.render.call(this);
      }
      _proxy(key) {
        const self = this
        Object.defineProperty(self, key, {
          configurable: true,
          enumerable: true,
          get: function proxyGetter () {
            return self._data[key]
          },
          set: function proxySetter (val) {
            self._data[key] = val
          }
        })
      }

       __toString__(val) {
        return val == null ? '' : typeof val === 'object' ? JSON.stringify(val, null, 2) : String(val);
      }
       __h__(tag, attr, children) {
          return VNode(tag, attr, children.map((child)=>{
            if(typeof child === 'string'){
              return VNode(undefined, undefined, undefined, child)
            }else{
              return child
            }
          }))
        }
    }
function parseMethod(methodlist){
  var self=this;
  for(let key in methodlist){
    if(methodlist.hasOwnProperty(key)){
      let func=methodlist[key];
      methodlist[key]=(function(){
        return function(){
          func.apply(self._data,arguments);
        }
      })();
    }
  }
}

    function observer(value){
      Object.keys(value).forEach((key) => {
        //增加复杂对象的支持
        let tmpobj=value[key];
        if(typeof tmpobj ==="object"){
          observer(tmpobj);
        }
        defineReactive(value, key, value[key])
      })
    }

    function defineReactive(obj, key, val, cb) {
      const dep = new Dep()
    //val 属于此函数中的闭包
      Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: true,
        get: ()=>{
          if(Dep.target){
            dep.add(Dep.target);
          }
          // Dep.target=null;
            return val;
        },
        set:newVal=> {
          if(newVal === val)
              return
           val = newVal;
           dep.notify()
          // cb.apply(scopeThis)
        }
      })
    }

    var demo = new Vue({
      el: '#demo',
      data: {
        text: 123,
        dd:111
      },
      render(){
     return this.__h__('div', {}, [
      this.__h__('span', {}, [this.__toString__(this.text)])
    ])
  }
    })

     setTimeout(function(){
       demo.text = 444
     }, 3000)